{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "jupyter": {
     "is_executing": true
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Got 9 Ford cars from opendbc\n"
     ]
    }
   ],
   "source": [
    "\"\"\"In this example, we use the public comma car segments database to check if vin fingerprinting is feasible for ford.\"\"\"\n",
    "\n",
    "from openpilot.tools.lib.logreader import LogReader, comma_car_segments_source\n",
    "from openpilot.tools.lib.comma_car_segments import get_comma_car_segments_database\n",
    "from opendbc.car.ford.values import CAR\n",
    "\n",
    "database = get_comma_car_segments_database()\n",
    "\n",
    "platforms = [c.value for c in CAR]\n",
    "print(f\"Got {len(platforms)} Ford cars from opendbc\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Adapted from https://github.com/commaai/openpilot/issues/31052#issuecomment-1902690083\n",
    "\n",
    "MODEL_YEAR_CODES = {'M': 2021, 'N': 2022, 'P': 2023, 'R': 2024, 'S': 2025}\n",
    "\n",
    "\n",
    "F150_CODES = ['F1C', 'F1E', 'W1C', 'W1E', 'X1C', 'X1E', 'W1R', 'W1P', 'W1S', 'W1T']\n",
    "LIGHTNING_CODES = ['L', 'V']\n",
    "MACHE_CODES = ['K1R', 'K1S', 'K2S', 'K3R', 'K3S', 'K4S']\n",
    "\n",
    "FORD_VIN_START = ['1FT', '3FM', '5LM']\n",
    "\n",
    "def ford_vin_fingerprint(vin): # Check if it's a Ford vehicle and determine the model\n",
    "  vin_positions_567 = vin[4:7]\n",
    "\n",
    "  if vin.startswith('1FT'):\n",
    "    if vin_positions_567 in F150_CODES:\n",
    "      if vin[7] in LIGHTNING_CODES:\n",
    "        return f\"FORD F-150 LIGHTNING 1ST GEN\"\n",
    "      else:\n",
    "        return f\"FORD F-150 14TH GEN\"\n",
    "  elif vin.startswith('3FM'):\n",
    "    if vin_positions_567 in MACHE_CODES:\n",
    "      return f\"FORD MUSTANG MACH-E 1ST GEN\"\n",
    "  elif vin.startswith('5LM'):\n",
    "    pass\n",
    "\n",
    "  return \"mock\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting segments from commaCarSegments dataset:\n",
      "Got 287 segments for platform FORD_BRONCO_SPORT_MK1, sampling 5 segments\n",
      "Got 137 segments for platform FORD_ESCAPE_MK4, sampling 5 segments\n",
      "Got 1041 segments for platform FORD_EXPLORER_MK6, sampling 5 segments\n",
      "Got 5 segments for platform FORD_F_150_MK14, sampling 5 segments\n",
      "Got 3 segments for platform FORD_F_150_LIGHTNING_MK1, sampling 3 segments\n",
      "Got 56 segments for platform FORD_FOCUS_MK4, sampling 5 segments\n",
      "Got 637 segments for platform FORD_MAVERICK_MK1, sampling 5 segments\n",
      "Got 3 segments for platform FORD_MUSTANG_MACH_E_MK1, sampling 3 segments\n",
      "Skipping platform: FORD_RANGER_MK2, no data available\n",
      "Segment collection finished\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "MAX_SEGS_PER_PLATFORM = 5\n",
    "\n",
    "VINS_TO_CHECK = set()\n",
    "\n",
    "print(\"Collecting segments from commaCarSegments dataset:\")\n",
    "for platform in platforms:\n",
    "  if platform not in database:\n",
    "    print(f\"Skipping platform: {platform}, no data available\")\n",
    "    continue\n",
    "\n",
    "  all_segments = database[platform]\n",
    "\n",
    "  NUM_SEGMENTS = min(len(all_segments), MAX_SEGS_PER_PLATFORM)\n",
    "\n",
    "  print(f\"Got {len(all_segments)} segments for platform {platform}, sampling {NUM_SEGMENTS} segments\")\n",
    "\n",
    "  segments = random.sample(all_segments, NUM_SEGMENTS)\n",
    "\n",
    "  for segment in segments:\n",
    "    lr = LogReader(segment, sources=[comma_car_segments_source])\n",
    "    CP = lr.first(\"carParams\")\n",
    "    if \"FORD\" not in CP.carFingerprint:\n",
    "      print(segment, CP.carFingerprint)\n",
    "    VINS_TO_CHECK.add((CP.carVin, CP.carFingerprint))\n",
    "\n",
    "print(\"Segment collection finished\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "vin: 3FMCR9B69NRXXXXXX real platform: FORD BRONCO SPORT 1ST GEN          determined platform: mock                              correct: False\n",
      "vin: 00000000000XXXXXX real platform: FORD F-150 14TH GEN                determined platform: mock                              correct: False\n",
      "vin: 1FMCU9J94MUXXXXXX real platform: FORD ESCAPE 4TH GEN                determined platform: mock                              correct: False\n",
      "vin: 3FMTK3SU0MMXXXXXX real platform: FORD MUSTANG MACH-E 1ST GEN        determined platform: FORD MUSTANG MACH-E 1ST GEN       correct: True\n",
      "vin: 1FM5K8HC7MGXXXXXX real platform: FORD EXPLORER 6TH GEN              determined platform: mock                              correct: False\n",
      "vin: 5LM5J7XC9LGXXXXXX real platform: FORD EXPLORER 6TH GEN              determined platform: mock                              correct: False\n",
      "vin: 1FTVW1EL4NWXXXXXX real platform: FORD F-150 LIGHTNING 1ST GEN       determined platform: FORD F-150 LIGHTNING 1ST GEN      correct: True\n",
      "vin: WF0NXXGCHNJXXXXXX real platform: FORD FOCUS 4TH GEN                 determined platform: mock                              correct: False\n",
      "vin: 3FTTW8E99NRXXXXXX real platform: FORD MAVERICK 1ST GEN              determined platform: mock                              correct: False\n",
      "vin: 1FM5K8GC7LGXXXXXX real platform: FORD EXPLORER 6TH GEN              determined platform: mock                              correct: False\n",
      "vin: 3FTTW8E33NRXXXXXX real platform: FORD MAVERICK 1ST GEN              determined platform: mock                              correct: False\n",
      "vin: 5LM5J7XC1LGXXXXXX real platform: FORD EXPLORER 6TH GEN              determined platform: mock                              correct: False\n",
      "vin: 3FTTW8E3XPRXXXXXX real platform: FORD MAVERICK 1ST GEN              determined platform: mock                              correct: False\n"
     ]
    }
   ],
   "source": [
    "for vin, real_fingerprint in VINS_TO_CHECK:\n",
    "  determined_fingerprint = ford_vin_fingerprint(vin)\n",
    "  print(f\"vin: {vin} real platform: {real_fingerprint: <30}     determined platform: {determined_fingerprint: <30}    correct: {real_fingerprint == determined_fingerprint}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
